package com.dayatang.exam.domain;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

import com.dayatang.domain.AbstractEntity;
import com.dayatang.domain.QuerySettings;

/**
 * 题库类�?每个题库中包含多道题目，每道题目可分别属于不同题�?
 * @author yang
 *
 */
@Entity
@Table(name = "QUESTION_LIBS")
public class QuestionLib extends AbstractEntity implements Comparable<QuestionLib> {

	private static final long serialVersionUID = 4523148028592147199L;

	/**
	 * 题库名称
	 */
	private String name;

	/**
	 * 备注
	 */
	private String memo;

	/**
	 * 创建人
	 */
	@ManyToOne
	@JoinColumn(name = "CREATOR_ID")
	private User creator;

	/**
	 * 创建时间
	 */
	@Temporal(TemporalType.TIMESTAMP)
	private Date created;

	/**
	 * 试题的集合
	 */
	@OneToMany(cascade = CascadeType.ALL, mappedBy = "questionLib")
	private Set<Question> questions = new HashSet<Question>();

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

	public User getCreator() {
		return creator;
	}

	public void setCreator(User creator) {
		this.creator = creator;
	}

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	public Set<Question> getQuestions() {
		return questions;
	}

	public void addQuestion(Question question) {
		question.setQuestionLib(this);
		questions.add(question);
	}
	
	public void removeQuestion(Question question) {
		question.setQuestionLib(null);
		questions.remove(question);
	}

	public static QuestionLib get(Long id) {
		return getRepository().get(QuestionLib.class, id);
	}

	public static Collection<QuestionLib> list() {
		return getRepository().findAll(QuestionLib.class);
	}

	/**
	 * 查找指定时间范围内创建的题库
	 * @param fromDate
	 * @param toDate
	 * @return
	 */
	public static Collection<QuestionLib> findByCreated(Date fromDate, Date toDate) {
		return getRepository().find(QuerySettings.create(QuestionLib.class)
				.between("created", fromDate, toDate));
	}
	
	public <T extends Question> List<T> getQuestions(Class<T> questionClass) {
		return Question.findInLib(this, questionClass);
	}

	public int getSingleChoiceQuestionCount() {
		return  getQuestions(SingleChoiceQuestion.class).size();
	}

	public int getMultiChoiceQuestionCount() {
		return  getQuestions(MultiChoiceQuestion.class).size();
	}

	public int getJudgementQuestionCount() {
		return  getQuestions(JudgementQuestion.class).size();
	}

	public int getFillBlankQuestionCount() {
		return  getQuestions(FillBlankQuestion.class).size();
	}

	public int getQuizQuestionCount() {
		return  getQuestions(QuizQuestion.class).size();
	}

	/**
	 * 从题库中随机获取指定类型指定数量的试�?
	 * @param questionClass
	 * @param count
	 * @return
	 * @throws QuestionInsufficientException
	 */
	public <T extends Question> List<T> getRandomQuestions(Class<T> questionClass, int count) throws QuestionInsufficientException {
		return generateRandomSet(getQuestions(questionClass), count);
	}

	private <T extends Question> List<T> generateRandomSet(List<T> questions, int count) throws QuestionInsufficientException {
		int availableNumber = questions.size();
		if (count > availableNumber) {
			throw new QuestionInsufficientException("题库中可选题数量不足!");
		}
		Set<T> resultSet = new HashSet<T>();
		List<T> result = new ArrayList<T>();
		while (true) {
			int index = new Random().nextInt(availableNumber);
			if (resultSet.add(questions.get(index))) {
				result.add(questions.get(index));
			}
			if(resultSet.size() == count) {
				return result;
			}
		}
	}

	public int compareTo(QuestionLib other) {
		if (other == null) {
			return 1;
		}
		return getId().compareTo(other.getId());
	}

	@Override
	public boolean equals(final Object other) {
		if (!(other instanceof QuestionLib))
			return false;
		QuestionLib castOther = (QuestionLib) other;
		return new EqualsBuilder().append(getId(), castOther.getId()).append(name, castOther.name).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(getId()).append(name).toHashCode();
	}

	@Override
	public String toString() {
		return new ToStringBuilder(this).append("id", getId()).append("name", name).toString();
	}
}
